/*
 *  Created by Wu Heshun on 09-3-10.
 *  Copyright 2009 handcn. All rights reserved.
 *
 */
#include "graphic_public.h"
#include "Td_object.h"
#include "totem_obj_config.h"
#include <deque>
#include "game_logic.h"

using totem_destroyer::SpaceMgr;
using totem_destroyer::PolygonStaticObject;

template <typename T>
struct _create_obj
{
	static inline T* create(SpaceMgr * spaceManager, totem_obj_info_t *obj_info)
	{
		T *ret = NULL;
		ASSERT(obj_info->is_polygon);		
		ret =  spaceManager->create<T>();

		float_t area;
		point2d_t _verts[totem_obj_info_t::VERT_NUM];
		for(int i = 0; i < totem_obj_info_t::VERT_NUM; i++) _verts[i] = (float_t)obj_info->verts[i].x, (float_t)obj_info->verts[i].y;
		point2d_t gravity_center = polygon::GetPolygonCOG(_verts, totem_obj_info_t::VERT_NUM, area);		
		gravity_center = obj_info->pos.x, obj_info->pos.y;

		cpFloat mass = area * obj_info->density;
		ret->Initialize(spaceManager->m_space, mass, totem_obj_info_t::VERT_NUM, obj_info->verts, cpvzero, cpv(gravity_center[0], gravity_center[1]));

		ret->setTexture(obj_info->texture_name.c_str());
		ret->SetDefaultTextCoords();

		ret->SetActions();
		spaceManager->insert(ret->m_pShape);
		ret->SetFrictionAndElasticity(obj_info->friction, obj_info->elasticity);
		ret->GetBoby()->f = cpvmult(obj_info->force, area);
		return ret;

	}
};

template <typename T, typename OBJ_POINTER_T>
inline T* CreateObj(SpaceMgr * spaceManager, OBJ_POINTER_T obj_info) {
	totem_obj_info_t tmp = *obj_info;
	T *ret = _create_obj<T>::create(spaceManager, &tmp);
	ret->m_objInfo = &(*obj_info);
	return ret;
}

template <typename OBJ_POINTER_T>
inline TotemObject_t* CreateMainObj(SpaceMgr * spaceManager, OBJ_POINTER_T obj_info)
{
	TotemObject_t *ret = NULL;
	ASSERT(obj_info->is_polygon);
	//ASSERT(!obj_info->is_explosive);		
	ret =  spaceManager->create<TotemObject_t>();
	ret->setTexture(obj_info->texture_name.c_str());
	ret->SetDefaultTextCoords();
	boost::shared_ptr<texture_t> texture = ret->getTexture();

	float_t area;
	point2d_t _verts[dim(G_MAIN_OBJ_EDGES)];
	cpVect size = cpv(fabs(2 * obj_info->verts[0].x), fabs(2 * obj_info->verts[0].y));
	
	for(int i = 0; i < dim(G_MAIN_OBJ_EDGES); i++) {
		_verts[i] = (float_t)G_MAIN_OBJ_EDGES[i].x - size.x/2 + obj_info->pos.x, 
			size.y/2 - (float_t)G_MAIN_OBJ_EDGES[i].y + obj_info->pos.y;
	}

	point2d_t gravity_center = polygon::GetPolygonCOG(_verts, dim(G_MAIN_OBJ_EDGES), area);

	cpVect verts_minus_gravity_center[dim(G_MAIN_OBJ_EDGES)];
	for(int i = 0; i < dim(G_MAIN_OBJ_EDGES); i++) {
		verts_minus_gravity_center[i] = cpv(_verts[i][0] - gravity_center[0], _verts[i][1] - gravity_center[1]);
	}
	gravity_center = gravity_center[0] , gravity_center[1];
	cpFloat mass = area * obj_info->density;
	ret->Initialize(spaceManager->m_space, mass, dim(G_MAIN_OBJ_EDGES), verts_minus_gravity_center, cpvzero, cpv(gravity_center[0], gravity_center[1]));

	boost::shared_array<point2d_t> coords(new point2d_t[dim(G_MAIN_OBJ_EDGES)]);
	boost::shared_array<point2d_t> vts(new point2d_t[dim(G_MAIN_OBJ_EDGES)]);

#ifndef WIN32
	Texture2D * tex = texture->GetTexture();
	float_t cood_w = tex->getMaxT();
	float_t cood_h = tex->getMaxS();
#else
	float_t cood_w = ((float_t)texture->actual_width)/texture->width;
	float_t cood_h = ((float_t)texture->actual_height)/texture->height;
#endif		

	for(int i = 0; i < dim(G_MAIN_OBJ_EDGES); i++) {
		coords[i] = (float_t)(G_MAIN_OBJ_EDGES[i].x * cood_w / size.x), 
			(float_t)( ( G_MAIN_OBJ_EDGES[i].y) * cood_h / size.y);
	}

	ret->SetVertNum(dim(G_MAIN_OBJ_EDGES), vts, coords);

	ret->SetActions();
	ret->SetFrictionAndElasticity(obj_info->friction, obj_info->elasticity);
	ret->GetBoby()->f = cpvmult(obj_info->force, area);
	
	ret->m_objInfo = &(*obj_info);
	spaceManager->insert(ret->m_pShape);

	return ret;

}


//#define  IMG_CHOCOLATE "d:\\textures\\sky.tga"
//totem_obj_info_t OBJS[] = {
//
//	{{0, 0}, 1, 0.0, 1.0,  IMG_CHOCOLATE, true, true, {0, 0}, {{20, 100},{20, 150},  {70, 150}, {70, 100} }},
//	{{50, 100}, 1, 0.0, 1.0,  IMG_CHOCOLATE, true, true, {0, 0}, {{-20, 10},{-20, 60},  {30, 60}, {30, 10} }},
//
//};



using namespace std;

typedef maps::map_iterator_t map_iterator_t;


template<typename OBJ_POINTER_T>
void create_obj_from_config_data(SpaceMgr * m_spaceManager, OBJ_POINTER_T objs, int obj_num)
{
	for(int i = 0; i < obj_num; i++) {
		OBJ_POINTER_T curr = objs+i;
		if (string::npos != curr->texture_name.find(STR_MAIN_ICON)) {
			TotemObject_t *obj = CreateMainObj(m_spaceManager, curr);
			game_logic::addTotemObject(obj);
			obj->SetVerts();			
		}
		else if(curr->is_polygon) {
			if (curr->is_explosive) {
				if (curr->is_TNT) CreateObj<TNTObject>(m_spaceManager, curr);
				else CreateObj<PolygonObject>(m_spaceManager, curr);

			}
			else {
				CreateObj<PolygonStaticObject>(m_spaceManager, curr);				
			}
		
		}
		else {
			ASSERT(0);
		}
	}
}



extern object_base_info_t g_floor_info;
void chipmunk_test(SpaceMgr * spaceManager, bool repeat = false)
{
	for (int i = 1; i < dim(SCENE_EDGES); i++)
	{
		totem_destroyer::StaticEdgeObj *tmp = spaceManager->create<totem_destroyer::StaticEdgeObj>();
		tmp->Initialize(spaceManager->m_space, SCENE_EDGES[i-1].x, SCENE_EDGES[i-1].y, SCENE_EDGES[i].x, SCENE_EDGES[i].y);
		tmp->SetActions();
		spaceManager->insert(tmp->m_pShape);
		tmp->SetFrictionAndElasticity(g_floor_info.friction, g_floor_info.elasticity);
	}

	map_iterator_t begin, end;
	static int s_level = 0;
if (!repeat) {
#ifdef WIN32
	std::cout << "«Â ‰»Îπÿ ˝ " << std::endl;
	int index = 0;
	std::cin >> index;
	ASSERT(index >= 1);
#else
	int index = 1;
#endif
		s_level = index - 1;
	}
	maps::getMaps(s_level, begin, end);
	
	create_obj_from_config_data(spaceManager, begin, end-begin);
	//create_obj_from_config_data(spaceManager, begin, 1);
	//create_obj_from_config_data(spaceManager, OBJS, dim(OBJS));
}
void CreateObjs(SpaceMgr * spaceManager, int level)
{
	for (int i = 1; i < dim(SCENE_EDGES); i++)
	{
		totem_destroyer::StaticEdgeObj *tmp = spaceManager->create<totem_destroyer::StaticEdgeObj>();
		tmp->Initialize(spaceManager->m_space, SCENE_EDGES[i-1].x, SCENE_EDGES[i-1].y, SCENE_EDGES[i].x, SCENE_EDGES[i].y);
		tmp->SetActions();
		spaceManager->insert(tmp->m_pShape);
		tmp->SetFrictionAndElasticity(g_floor_info.friction, g_floor_info.elasticity);
	}
	map_iterator_t begin, end;
	maps::getMaps(level, begin, end);	
	create_obj_from_config_data(spaceManager, begin, end-begin);
}
